/*************************************************************************
 * Tic Tac Toe
 *
 * Author: Justin Sheppard
 * Student #: 200811917
 * E-Mail: justin.sheppard@mun.ca
 * ***********************************************************************/
package tictactoe;

import java.util.Random;

/** SmartAI *****************************************************************
 * 
 * A class that implements the AI interface. Unlike its life-loving, fun-loving
 * counter part, SmartAI wants to win. He's a lot better than DumbAI - he can block
 * and he knows how to win. But he's still only an amateur at the game; he hasn't
 * quite learned how to know when them nasty forks are about to happen.
 * 
 * ****************************************************************************/
public class SmartAI implements AI {
	private char aiPiece;
	private boolean aiIsX;
	private int i;
	private int j;

	/** Constructor *****************************************************************
	 * 
	 * Simply creates an object with a piece opposite of the player's.
	 * 
	 * @pre		-	
	 * @params	- aiIsX: True if the player wants to play as O
	 * @returns - 
	 * @post	- 
	 * ****************************************************************************/
	public SmartAI(boolean aiIsX){
		this.aiIsX = aiIsX;
		if(aiIsX){
			aiPiece = 'X';
		}else{
			aiPiece = 'O';
		}
	}

	/** isBlockOrWin *****************************************************************
	 * 
	 * A sort-of smelly piece of code that checks if there are any positions that the
	 * ai can place its piece to win or block, depending on the call. Does not work
	 * with forks.
	 * 
	 * @pre		-	
	 * @params	- b: Current board, used to test for player and empty positions.
	 * 			  aiIsX: Used to determine which piece to look for when blocking/winning
	 * 			  block: TRUE->Check for block; FALSE->Check for win. Check for block uses
	 * 					the same "algorithm" as check for win, only thing that changes is the
	 * 					piece we're looking for. So might as well reuse the code, eh?
	 * @returns - TRUE: If there's a block/win
	 * 			  FALSE: If not.
	 * @post	- 
	 * ****************************************************************************/
	private boolean isBlockOrWin(Board b, boolean aiIsX, boolean block){
		char piece = ' ';
		if((aiIsX && block) || (!aiIsX && !block)) //Conditions for looking for O's
			piece = 'O';
		else if((aiIsX && !block) || (!aiIsX && block)) //Conditons for looking for X's
			piece = 'X';		

		//Check rows
		for (int i = 0; i < 3; i++){	//Checks the 1st/2nd, 1st/3rd, and 2nd/3rd positions in each row.
			if((b.get(i, 0) == piece) && (b.get(i, 1) == piece) && (b.get(i, 2) == ' ')){
				this.i = i;	//The empty spots for the respective tests above.
				this.j = 2;
				return true;
			}
			if((b.get(i, 0) == piece) && (b.get(i, 2) == piece) && (b.get(i, 1) == ' ')){
				this.i = i;
				this.j = 1;
				return true;
			}
			if((b.get(i, 1) == piece) && (b.get(i, 2) == piece) && (b.get(i, 0) == ' ')){
				this.i = i;
				this.j = 0;
				return true;
			}
		}

		//Check cols
		for (int i = 0; i < 3; i++){ //Checks the 1st/2nd, 1st/3rd, and 2nd/3rd positions in each col.
			if((b.get(0, i) == piece) && (b.get(1, i) == piece) && (b.get(2, i) == ' ')){
				this.i = 2;
				this.j = i;
				return true;
			}
			if((b.get(0, i) == piece) && (b.get(2, i) == piece) && (b.get(1, i) == ' ')){
				this.i = 1;
				this.j = i;
				return true;
			}
			if((b.get(1, i) == piece) && (b.get(2, i) == piece) && (b.get(0, i) == ' ')){
				this.i = 0;
				this.j = i;
				return true;
			}
		}

		//Check diagnol
		if((b.get(0, 0) == piece) && (b.get(1, 1) == piece) && (b.get(2, 2) == ' ')){
			this.i = 2;
			this.j = 2;
			return true;
		}
		if((b.get(0, 0) == piece) && (b.get(2, 2) == piece) && (b.get(1, 1) == ' ')){
			this.i = 1;
			this.j = 1;
			return true;
		}
		if((b.get(1, 1) == piece) && (b.get(2, 2) == piece) && (b.get(0, 0) == ' ')){
			this.i = 0;
			this.j = 0;
			return true;
		}

		//Check anti-diagnol
		if((b.get(2, 0) == piece) && (b.get(1, 1) == piece) && (b.get(0, 2) == ' ')){
			this.i = 0;
			this.j = 2;
			return true;
		}
		if((b.get(2, 0) == piece) && (b.get(0, 2) == piece) && (b.get(1, 1) == ' ')){
			this.i = 1;
			this.j = 1;
			return true;
		}
		if((b.get(1, 1) == piece) && (b.get(0, 2) == piece) && (b.get(2, 0) == ' ')){
			this.i = 2;
			this.j = 0;
			return true;
		}

		return false;
	}

	/** chooseMove *****************************************************************
	 * 
	 * Checks for a win, then a block, else randomly places a piece in an open position.
	 * @pre		-	
	 * @params	- board: Used to check the current board's open positions
	 * @returns - The AI's Move with the corresponding row, col index and its piece.
	 * @post	-
	 * ****************************************************************************/
	@Override
	public Move chooseMove(Board board) {
		Move aiMove;
		Random gen = new Random();
		int i = gen.nextInt(3);
		int j = gen.nextInt(3);

		if(isBlockOrWin(board, aiIsX, false)){ //Check for a win
			i = this.i;
			j = this.j;
		}else if(isBlockOrWin(board, aiIsX, true)){ //Check for a block
			i = this.i;
			j = this.j;
		}else{ //Otherwise, put it somewhere random
			boolean empty = false;
			while(!empty)
				if(board.get(i, j) != ' '){
					i = gen.nextInt(3);
					j = gen.nextInt(3);
				}else{
					empty = true;
				}
		}

		aiMove = new Move(i, j, aiPiece);
		return aiMove;
	}

}
